home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue47 / System / Main.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1999-06-03  |  6.3 KB  |  225 lines

  1. unit Main;
  2.  
  3. interface
  4.  
  5. uses
  6.     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.     StdCtrls, ComCtrls, ExtCtrls;
  8.  
  9. const
  10.     // Magic signatures
  11.     D2Magic  =         $50505348;
  12.     D3Magic  =         $44518641;
  13.     D4Magic  =         $4768A6D8;
  14.     B3Magic  =         $475896C8;
  15.  
  16.     // DCU record tags
  17.     Tag_End           =        $61;
  18.     Tag_DFK_Source    =        $70;
  19.     Tag_DFK_Object    =           $71;
  20.     Tag_DFK_Resource  =           $72;
  21.     Tag_DFK_TheAdr    =           $73;
  22.  
  23. type
  24.     TForm1 = class(TForm)
  25.     Scan: TButton;
  26.     StatusBar1: TStatusBar;
  27.     TreeList: TListView;
  28.     procedure ScanClick(Sender: TObject);
  29.     procedure TreeListDblClick(Sender: TObject);
  30.     private
  31.     { Private declarations }
  32.         Scanning: Boolean;
  33.         procedure ScanDrive (const Path: String);
  34.         procedure FoundOne (const PathName: String);
  35.         function  DCUReadString (var p: PChar): String;
  36.         procedure DCUDumpDFKRecord (const Typ: String; var p: PChar);
  37.         function  DCUDecodeNum (var p: PChar): Integer;
  38.     public
  39.       { Public declarations }
  40.     end;
  41.  
  42. var
  43.   Form1: TForm1;
  44.  
  45. implementation
  46.  
  47. {$R *.DFM}
  48.  
  49. procedure TForm1.ScanClick (Sender: TObject);
  50. var
  51.     p: PChar;
  52.     szBuff: array [0..255] of Char;
  53. begin
  54.     Scanning := not Scanning;
  55.     if Scanning then begin
  56.         Scan.Caption := 'Stop Scan!';
  57.         Screen.Cursor := crHourGlass;
  58.         TreeList.Items.Clear;
  59.         TreeList.Items.BeginUpdate;
  60.  
  61.         try
  62.             p := szBuff;
  63.             GetLogicalDriveStrings (sizeof (szBuff), szBuff);
  64.             while Scanning and (p^ <> #0) do begin
  65.                 if GetDriveType (p) = Drive_Fixed then ScanDrive (p);
  66.                 Inc (p, 4);
  67.             end;
  68.         finally
  69.             Scanning := False;
  70.             Scan.Caption := 'Scan!';
  71.             Screen.Cursor := crDefault;
  72.             TreeList.Items.EndUpdate;
  73.         end;
  74.     end;
  75. end;
  76.  
  77. procedure TForm1.FoundOne (const PathName: String);
  78. var
  79.     eof: Byte;
  80.     S: String;
  81.     Valid: Boolean;
  82.     fs: TFileStream;
  83.     Item: TListItem;
  84.     Magic: array [0..3] of LongInt;
  85. begin
  86.     fs := TFileStream.Create (PathName, fmOpenRead);
  87.     try
  88.         fs.Read (Magic, sizeof (Magic));
  89.         fs.Position := fs.Size - 1;
  90.         fs.Read (eof, sizeof (eof));
  91.         Valid := (Magic [1] = fs.Size) and (eof = Tag_End);
  92.         if (Magic [0] = D2Magic) and ((Magic [3] and $ff) <> 0) then begin
  93.             ShowMessage (PathName + ' is invalid Delphi2 DCU.  Skipping...');
  94.             Valid := False;
  95.         end;
  96.     finally
  97.         fs.Free;
  98.     end;
  99.  
  100.     if Valid then begin
  101.         Item := TreeList.Items.Add;
  102.         Item.Caption := PathName;
  103.         case Magic [0] of
  104.             D2Magic:   S := 'Delphi 2';
  105.             D3Magic:   S := 'Delphi 3';
  106.             D4Magic:   S := 'Delphi 4';
  107.             B3Magic:   S := 'C++ Builder 3';
  108.             else       S := '???' + IntToHex (Magic [0], 8);
  109.         end;
  110.         Item.SubItems.Add (S);
  111.  
  112.         if Magic [2] = $ffffffff then S := 'Invalid date/time' else
  113.         S := FormatDateTime ('dddd, mmmm d, yyyy, hh:mm AM/PM', FileDateToDateTime (Magic [2]));
  114.         Item.SubItems.Add (S);
  115.     end;
  116. end;
  117.  
  118. procedure TForm1.ScanDrive (const Path: String);
  119. var
  120.     Res: Integer;
  121.     SR: TSearchRec;
  122. begin
  123.     Application.ProcessMessages;
  124.     StatusBar1.Panels [0].Text := 'Scanning ' + Path;
  125.     Res := FindFirst (Path + '*.*', faAnyFile, SR);
  126.     try
  127.         while Scanning and (Res = 0) do begin
  128.             if SR.Name [1] <> '.' then begin
  129.                 if UpperCase (ExtractFileExt (SR.Name)) = '.DCU' then FoundOne (Path + SR.Name) else
  130.                 if ((SR.Attr and faDirectory) <> 0) then ScanDrive (Path + SR.Name + '\');
  131.             end;
  132.             Res := FindNext (SR);
  133.         end;
  134.     finally
  135.         FindClose (SR);
  136.     end;
  137. end;
  138.  
  139. function TForm1.DCUReadString (var p: PChar): String;
  140. var
  141.     Len: Byte;
  142. begin
  143.     Result := '';
  144.     Len := Ord (p^);  Inc (p);
  145.     while Len <> 0 do begin
  146.         Result := Result + p^;
  147.         Inc (p);  Dec (Len);
  148.     end;
  149. end;
  150.  
  151. function  TForm1.DCUDecodeNum (var p: PChar): Integer;
  152. const
  153.     SizeNum: array [0..15] of Byte = ( 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, 5 );
  154.     ShiftNum: array [0..15] of Byte = ( 25, 18, 25, 11, 25, 18, 25, 4, 25, 18, 25, 11, 25, 18, 25, 0 );
  155. var
  156.     Idx: Byte;
  157. begin
  158.     Idx := Ord (p^) and 15;
  159.     Inc (p, SizeNum [Idx]);
  160.     Result := PLongInt (p - 4)^ shr ShiftNum [Idx];
  161. end;
  162.  
  163. procedure TForm1.DCUDumpDFKRecord (const Typ: String; var p: PChar);
  164. var
  165.     s: String;
  166.     modtime: LongInt;
  167. begin
  168.     s := Typ + ' = ' + DCUReadString (p) + #10;
  169.     try
  170.         modtime := PLongInt (p)^;  Inc (p, 4);
  171.         s := s + 'ModTime = ' + FormatDateTime ('dddd, mmmm d, yyyy, hh:mm AM/PM', FileDateToDateTime (modtime)) + #10;
  172.     except
  173.         { Eat exceptions if modtime is invalid } ;
  174.     end;
  175.  
  176.     s := s + 'File index = ' + IntToStr (DCUDecodeNum (p));
  177.     ShowMessage (s);
  178. end;
  179.  
  180. procedure TForm1.TreeListDblClick(Sender: TObject);
  181. var
  182.     Tag: Byte;
  183.     Buff, p: PChar;
  184.     Item: TListItem;
  185.     fs: TFileStream;
  186. begin
  187.     Item := TreeList.Selected;
  188.     if Item = Nil then Exit;
  189.     fs := TFileStream.Create (Item.Caption, fmOpenRead);
  190.     try
  191.        GetMem (Buff, fs.Size);
  192.        fs.Read (Buff^, fs.Size);
  193.     finally
  194.        fs.Free;
  195.     end;
  196.  
  197.     // point at first byte of interest in DCU image
  198.     p := Buff + 12;
  199.     // Skip over Delphi 2's always-zero string
  200.     if PLongInt(Buff)^ = D2Magic then Inc (p);
  201.  
  202.     try
  203.         while True do begin
  204.             Tag := Ord (p^);  Inc (p);
  205.             case Tag of
  206.                 Tag_End:           Exit;  // All done!
  207.                 Tag_DFK_Source:    DCUDumpDFKRecord ('Source File', p);
  208.                 Tag_DFK_Object:    DCUDumpDFKRecord ('Object File', p);
  209.                 Tag_DFK_Resource:  DCUDumpDFKRecord ('Resource File', p);
  210.                 Tag_DFK_TheAdr:    DCUDumpDFKRecord ('Tag_DFK_TheAdr ????', p);
  211.                 else               begin
  212.                                        ShowMessage (Format ('Unknown tag $%x', [Tag]));
  213.                                        Exit;
  214.                                    end;
  215.             end;
  216.         end;
  217.     finally
  218.         FreeMem (Buff);
  219.     end;
  220. end;
  221.  
  222. end.
  223.  
  224.  
  225.